"""
注解工具类
提供扫描对象中注解的工具方法
"""

import inspect
import json


class SensitiveField:
    """
    敏感字段标记类，支持嵌套字段路径
    
    例如：
    SensitiveField("base_info.contact_info.contact_name")
    表示base_info字典中的contact_info字典中的contact_name字段
    """
    
    def __init__(self, field_path):
        """
        初始化敏感字段
        
        Args:
            field_path: 字段路径，使用点号分隔嵌套字段
        """
        self.field_path = field_path
        # 分解路径为各级字段名
        self.parts = field_path.split('.')
        # 顶级字段名
        self.top_field = self.parts[0] if self.parts else None

    def __str__(self):
        return self.field_path
        
    def __repr__(self):
        return f"SensitiveField('{self.field_path}')"


def get_sensitive_fields(obj):
    """
    获取对象中标记为敏感的字段
    
    Args:
        obj: 目标对象
        
    Returns:
        敏感字段列表
    """
    # 首先检查对象是否有自定义的get_sensitive_fields方法
    if hasattr(obj, 'get_sensitive_fields') and callable(getattr(obj, 'get_sensitive_fields')):
        return obj.get_sensitive_fields()
    
    # 如果没有自定义方法，则检查类级别的_encrypt_flag
    if not hasattr(obj.__class__, '_encrypt_flag'):
        return []
    
    sensitive_fields = []
    
    # 扫描类属性和方法
    for name, member in inspect.getmembers(obj.__class__):
        if hasattr(member, '_sensitive_field'):
            field_name = getattr(member, '_field_name', name)
            sensitive_fields.append(field_name)
            
    return sensitive_fields


def requires_encrypt(obj):
    """
    检查对象是否需要加密
    
    Args:
        obj: 目标对象
        
    Returns:
        是否需要加密
    """
    return hasattr(obj.__class__, '_encrypt_flag')


def requires_decrypt(obj):
    """
    检查对象是否需要解密
    
    Args:
        obj: 目标对象
        
    Returns:
        是否需要解密
    """
    return hasattr(obj.__class__, '_decrypt_flag')


# 装饰器定义
def Encrypt(cls):
    """
    类装饰器，标记类需要加密
    
    Args:
        cls: 被装饰的类
        
    Returns:
        被装饰的类，添加了_encrypt_flag属性
    """
    cls._encrypt_flag = True
    return cls


def Decrypt(cls):
    """
    类装饰器，标记类需要解密
    
    Args:
        cls: 被装饰的类
        
    Returns:
        被装饰的类，添加了_decrypt_flag属性
    """
    cls._decrypt_flag = True
    return cls


def Sensitive(func):
    """
    方法装饰器，标记方法返回的字段为敏感字段
    
    Args:
        func: 被装饰的方法
        
    Returns:
        被装饰的方法，添加了_sensitive_field属性
    """
    func._sensitive_field = True
    # 从方法名获取字段名，例如get_card_no -> card_no
    if func.__name__.startswith('get_'):
        func._field_name = func.__name__[4:]
    else:
        func._field_name = func.__name__
    return func


def encrypt_nested_fields(data, field_paths, encrypt_func):
    """
    加密嵌套字段
    
    Args:
        data: 待加密的数据字典
        field_paths: 敏感字段路径列表，可以是字符串或SensitiveField对象
        encrypt_func: 加密函数，接收字符串参数并返回加密后的字符串
        
    Returns:
        加密后的数据字典
    """
    if not data or not isinstance(data, dict):
        return data
    
    result = data.copy()
    
    for field_path in field_paths:
        if isinstance(field_path, SensitiveField):
            path_parts = field_path.parts
        else:
            path_parts = field_path.split('.')
        
        if not path_parts:
            continue
            
        # 处理嵌套路径
        if len(path_parts) > 1:
            top_field = path_parts[0]
            sub_path = '.'.join(path_parts[1:])
            
            if top_field in result and result[top_field] is not None:
                # 递归处理嵌套字段
                if isinstance(result[top_field], dict):
                    result[top_field] = encrypt_nested_fields(
                        result[top_field], 
                        [sub_path], 
                        encrypt_func
                    )
        else:
            # 直接字段
            field = path_parts[0]
            if field in result and result[field] is not None:
                value = result[field]
                # 如果是字典或列表，先转为JSON字符串
                if isinstance(value, (dict, list)):
                    value = json.dumps(value, ensure_ascii=False)
                
                # 加密字符串值
                if isinstance(value, str):
                    result[field] = encrypt_func(value)
    
    return result 